package com.gitee.huxing.course.netty.gateway.factory.request;

import com.gitee.huxing.course.netty.client.HttpCreateBuilder;
import com.gitee.huxing.course.netty.client.NettyClient;
import com.gitee.huxing.course.netty.gateway.factory.BusinessFactory;
import com.gitee.huxing.course.netty.gateway.filter.HttpHeaderRequestFilter;
import com.gitee.huxing.course.netty.gateway.filter.HttpRequestFilter;
import com.gitee.huxing.course.netty.gateway.router.NettyRouter;
import com.gitee.huxing.course.netty.threadpool.ThreadPool;
import io.netty.buffer.Unpooled;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.http.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static io.netty.handler.codec.http.HttpHeaderNames.CONNECTION;
import static io.netty.handler.codec.http.HttpHeaderValues.KEEP_ALIVE;
import static io.netty.handler.codec.http.HttpResponseStatus.NO_CONTENT;
import static io.netty.handler.codec.http.HttpResponseStatus.OK;
import static io.netty.handler.codec.http.HttpVersion.HTTP_1_1;

/**
 * @Description:
 * @ProjectName: JavaCourse
 * @Package: com.gitee.huxing.course.netty.gateway.factory
 * @ClassName: RequestFactory
 * @Author: huxing
 * @DateTime: 2021-08-21 下午3:53
 */
@Slf4j
@Component
@ConditionalOnBean(name = "requestFactory")
public class RequestFactory extends BusinessFactory<FullHttpRequest, ChannelHandlerContext, HttpRequestFilter> {

    @PostConstruct
    public void init(){
        // 设置过滤列表
        List<HttpRequestFilter> filters = new ArrayList<>();
        filters.add(new HttpHeaderRequestFilter());
        setFilters(filters);
        // 设置路由
        setRouter(new NettyRouter());
    }

    @Override
    public void processBussiness(FullHttpRequest request, ChannelHandlerContext channel) {
        // 返回的时候需要先处理过滤消息
        String message = request.content().toString(StandardCharsets.UTF_8);
        log.info("网关转发请求消息: {}", request.content().toString(StandardCharsets.UTF_8));
       try {
           FullHttpRequest body = (FullHttpRequest) new HttpCreateBuilder()
                   .createGetRequest(message, request.uri());
           this.process(body, channel);
       } catch (Exception ex){
           ex.printStackTrace();
       }
    }

    @Override
    public FullHttpRequest processFilter(FullHttpRequest request, List<HttpRequestFilter> filters) {
        for (HttpRequestFilter filter : filters){
            filter.filter(request, null);
        }
        return request;
    }

    @Override
    public void processRouter(FullHttpRequest request) {
        try {
            this.getRouter().router(request);
        } catch (Exception ex){
            ex.printStackTrace();
        }
    }

    @Override
    public void send(FullHttpRequest request, ChannelHandlerContext context){
        try {
            // 处理发送
            String host = request.headers().get("host");
            int port = request.headers().getInt("port");
            log.info("发送路径: {}:{}", host, port);
            // 取 1 - 100的随机数
            int random = new Random().nextInt(200);
            NettyClient client = NettyClient.build(host, port, random,context);
            // 获取通信渠道
            Channel channel = client.getChannel();
            // 转发处理
            channel.writeAndFlush(request);
        } catch (Exception ex){
            ex.printStackTrace();
            log.info("netty网关转发出错");
        }
    }

    @Override
    public void err(FullHttpRequest request, ChannelHandlerContext ctx, String err) {
        FullHttpResponse response = null;
        try {
            response = new DefaultFullHttpResponse(HTTP_1_1, OK,
                    Unpooled.wrappedBuffer(err.getBytes(StandardCharsets.UTF_8)));
            response.headers().set("Content-Type", "application/json");
            response.headers().setInt("Content-Length",
                    response.content().readableBytes());
        } catch (Exception ex){
            log.error("处理出错: " + ex.getMessage());
            response = new DefaultFullHttpResponse(HTTP_1_1, NO_CONTENT);
        } finally {
            if (request != null){
                if(!HttpUtil.isKeepAlive(request)){
                    ctx.write(response).addListener(ChannelFutureListener.CLOSE);
                } else {
                    response.headers().set(CONNECTION, KEEP_ALIVE);
                    ctx.write(response);
                }
            }
            ctx.flush();
        }
    }
}
